International aid may take the form of multilateral aid – provided through international bodies such as the UN, or NGOs such as Oxfam – or bilateral aid, which operates on a government-to-government basis. There is considerable debate about whether international aid works, in the sense of reducing poverty and stimulating development.

However, the effectiveness of aid is often diluted by corruption. Aid is invariably channeled through the governments of recipient countries, in which power is often concentrated in the hands of a few politicians and bureaucrats, and the mechanisms of accountability are, at best, poorly developed. This tends to benefit corrupt leaders and elites rather than the people, projects and programs for which it was intended.

The hypothesis that foreign aid can promote growth in developing countries was explored, using panel data series for foreign aid, while accounting for regional differences in Asian, African, Latin American, and the Caribbean countries as well as the differences in income levels, the results of this study also indicate that foreign aid has mixed effects on economic growth in developing countries.

This study examines the relationships between foreign aid, institutional structure, and economic performance for 80 countries in Europe, America, Africa, and Asia. It is found that official development assistance and the quality of institutional structure in the sample countries affect economic growth positively.

Cargando Librerias

Algunas librerias y paquetes usados para obtener y descargar los datos

library(tidyverse) # manejo de dataframes
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(WDI)       # libreria para acceder a metadata de banco mundial
library(readxl)    # leer archivos de excel
library(readr)     # leer archivos csv
library(visdat)    # visualizacion de datos como graficos
library(plotly)    # graficos
## 
## Adjuntando el paquete: 'plotly'
## 
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## The following object is masked from 'package:graphics':
## 
##     layout
library(purrr)     # funcion map

Obtener datos

Datos para paises bajos ingresos sean utilizados, segun clasificación del banco mundial, hay 26 paises de bajos ingresos y 51 de ingresos medios bajos

country_class <- read_excel("CLASS.xlsx")

country_class %>%
  filter(!is.na(Region), !is.na(`Income group`)) %>%
  group_by(`Income group`) %>%
  summarise(countries = n())

Listado de paises a analisar:

my_countries <- country_class %>%
  filter(!is.na(Region), `Income group` %in% c('Low income', 'Lower middle income')) %>%
  select(Code)
my_countries

Hacer la respectiva asociacion de nombres iso3c e iso2c

my_countries$iso2c <- WDI_data$country %>%
  filter(iso3c %in% my_countries$Code) %>%
  .$iso2c
my_countries

Datos del banco mundial (para ODA y los indices de gobernanza) y el Human Development Reports API son descargados desde scripts de Python. Son almacenados en archivos CSV y luego son cargados aqui:

HDI

datos_HDI <- read_csv("datos_python_HDI.csv", col_names = c('Code', 'iso2c', 'indicator', 'year', 'value'), 
                      col_types = list(col_character(), col_character(), col_character(), col_double(), col_double()))

hdi_indicators <- datos_HDI %>% distinct(indicator) %>% .$indicator

ODA

oda_indicators <- c(
'DT_ODA_ALLD_CD',
'DT_ODA_ALLD_KD',
'DT_ODA_OATL_CD',
'DT_ODA_OATL_KD',
'DT_ODA_ODAT_CD',
'DT_ODA_ODAT_GI_ZS',
'DT_ODA_ODAT_GN_ZS',
'DT_ODA_ODAT_KD',
'DT_ODA_ODAT_MP_ZS',
'DT_ODA_ODAT_PC_ZS',
'DT_ODA_ODAT_XP_ZS'
)
gob_indicators <- c(
'CC_EST',
'CC_NO_SRC',
'CC_PER_RNK',
'CC_PER_RNK_LOWER',
'CC_PER_RNK_UPPER',
'CC_STD_ERR',
'GE_EST',
'GE_NO_SRC',
'GE_PER_RNK',
'GE_PER_RNK_LOWER',
'GE_PER_RNK_UPPER',
'GE_STD_ERR',
'PV_EST',
'PV_NO_SRC',
'PV_PER_RNK',
'PV_PER_RNK_LOWER',
'PV_PER_RNK_UPPER',
'PV_STD_ERR',
'RQ_EST',
'RQ_NO_SRC',
'RQ_PER_RNK',
'RQ_PER_RNK_LOWER',
'RQ_PER_RNK_UPPER',
'RQ_STD_ERR',
'RL_EST')

datos_WB <- data.frame(indicator = character(), iso2c = character(), year = double(), value = double())

suppressWarnings(
  for (indicator in c(oda_indicators, gob_indicators)) {
    datos_WB <- rbind(datos_WB, read_csv(paste("datos_python", indicator, ".csv", sep =''), 
                                           col_names = c('indicator', 'iso2c', 'year', 'value'),
                                           col_types = list(col_character(), col_character(), col_double(), col_double())))
  }
)

Manipulacion de Datos

Transformar la estructura de los datos para una mejor comprension

datos_paper <- rbind(datos_WB, datos_HDI %>% select(indicator, iso2c, year, value)) %>%
  pivot_wider(names_from = indicator, values_from = value)

Revisar que datos estan como faltantes

vis_dat(datos_paper %>% select(all_of(gsub("_", ".", oda_indicators)))) 

  # DT.ODA.OATL.CD and DT.ODA.OATL.KD faltan
  # DT.ODA.ODAT.GI.ZS, DT.ODA.ODAT.GN.ZS, DT.ODA.ODAT.MP.ZS and DT.ODA.ODAT.XP.ZS tienen faltas
  # Un par de ocurrencias pais-año que faltan datos
vis_dat(datos_paper %>% arrange(year) %>%
          select(all_of(gsub("_", ".", gob_indicators)))) 

  # Datos del 2000 para atras tienen espacios faltantes 
vis_dat(datos_paper %>%
          select(all_of(hdi_indicators))) 

  # abr, co2_prod, le, le_f, le_m, mmr son las pocas categorias sin datos faltantes
vis_dat(datos_paper %>% arrange(year) %>% select(hdi)) 

  # hdi faltante en multiples ocaciones

Tomando en cuenta los datos faltantes, hacer filtros para seleccionar una muestra mas pequeña

datos_paper %>% filter(is.na(DT.ODA.ALLD.CD)) ## SS (South Sudan) y ZW (Zimbabwe) faltantes de ODA y GOB indicators
datos_paper %>% filter(!iso2c %in% c('SS', 'ZW')) %>% filter(is.na(CC.EST)) %>% group_by(year) %>% summarise(times = n())
  # para años 1995, 1997, 1999 y 2001 no hay registros de GOB
  # 1996, 1998, 2000, 2002 and 2003 tiene algunos paises sin datos
datos_paper %>% arrange(year) %>% filter(!iso2c %in% c('SS', 'ZW'), !year %in% c(1995, 1997, 1999, 2001)) %>%
                filter(is.na(CC.EST)) # FM (Micronesia), KI (Kiribati) y TL (Timor-Leste) no tiene GOB in en estos años 
                                      # tambien CV (Cabo Verde) and SB (Solomon Islands) no registro GOB en 2000 - 2003

Ver datos aplicando los filtros determinados en las busquedas pasadas antes del 2001 suele tener informacion faltante BT (Bhutan), ER (Eritrea), GW (Guinea-Bissau), KP (North Korea), LB (Lebanon), NG (Nigeria), PS (Palestine), SO (Somalia), VU (Vanuatu) son paises sin registro de hdi

datos_paper %>% 
          arrange(iso2c) %>% 
          filter(!iso2c %in% c('SS','ZW','BT','ER','GW','KP','LB','NG','PS','SO','VU','FM','KI','TL','CB','CV','SB'), 
                 !year %in% c(1995, 1996, 1997, 1998, 1999, 2000, 2001)) %>%
          select(iso2c, year, hdi,
                 all_of(gsub("_", ".", gob_indicators))
                 )
vis_dat(datos_paper %>% 
        filter(!iso2c %in% c('SS', 'ZW', 'BT', 'ER', 'GW', 'KP', 'LB', 'NG', 'PS', 'SO', 'VU', 'FM', 'KI', 'TL', 'CV', 'SB'),
               !year %in% c(1995, 1996, 1997, 1998, 1999, 2000, 2001)) %>%
        select(iso2c, year, hdi, DT.ODA.ALLD.CD, DT.ODA.ALLD.KD, DT.ODA.ODAT.CD, DT.ODA.ODAT.KD, DT.ODA.ODAT.PC.ZS,
               all_of(gsub("_", ".", gob_indicators))
               ))

De 1925 observaciones reducimos a 1098

datos_model <- datos_paper %>% 
        filter(!iso2c %in% c('SS', 'ZW', 'BT', 'ER', 'GW', 'KP', 'LB', 'NG', 'PS', 'SO', 'VU', 'FM', 'KI', 'TL', 'CV', 'SB'),
               !year %in% c(1995, 1996, 1997, 1998, 1999, 2000, 2001)) %>%
        select(iso2c, year, hdi, DT.ODA.ALLD.CD, DT.ODA.ALLD.KD, DT.ODA.ODAT.CD, DT.ODA.ODAT.KD, DT.ODA.ODAT.PC.ZS,
               all_of(gsub("_", ".", gob_indicators))
               )

Probando un modelo sencillo Minimos cuadrados

model <- lm(hdi ~ DT.ODA.ALLD.CD + CC.EST + GE.EST + PV.EST + RQ.EST + RL.EST, data=datos_model)
summary(model)
## 
## Call:
## lm(formula = hdi ~ DT.ODA.ALLD.CD + CC.EST + GE.EST + PV.EST + 
##     RQ.EST + RL.EST, data = datos_model)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.291363 -0.060809  0.001437  0.062167  0.195139 
## 
## Coefficients:
##                  Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     5.881e-01  5.818e-03 101.081  < 2e-16 ***
## DT.ODA.ALLD.CD  2.008e-12  2.589e-12   0.776  0.43815    
## CC.EST         -6.896e-02  1.085e-02  -6.355 3.05e-10 ***
## GE.EST          1.533e-01  1.107e-02  13.849  < 2e-16 ***
## PV.EST          9.200e-03  4.513e-03   2.039  0.04172 *  
## RQ.EST         -3.501e-02  1.065e-02  -3.288  0.00104 ** 
## RL.EST          2.094e-02  1.204e-02   1.738  0.08243 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.08902 on 1091 degrees of freedom
## Multiple R-squared:  0.2893, Adjusted R-squared:  0.2854 
## F-statistic:    74 on 6 and 1091 DF,  p-value: < 2.2e-16

Todas las variables son significativas al 95% excepto ODA

Se revisara las relaciones entre las variables graficamente

#Visualizacion de datos

my_plot  <- list()

for (col in colnames(datos_model)[4:33]) {
  my_plot[[col]] <- plot_ly(x = datos_model[[col]], y = datos_model[[3]],
                            type = 'scatter', mode = 'markers', name = paste(col, "vs HDI"))  
}


subplot(my_plot[1:5], nrows = 2, margin = 0.05) %>% layout(title = 'ODA vs HDI')
subplot(my_plot[6:11], nrows = 2, margin = 0.05) %>% layout(title = 'CC vs HDI')
subplot(my_plot[12:17], nrows = 2, margin = 0.05) %>% layout(title = 'GE vs HDI')
subplot(my_plot[18:23], nrows = 2, margin = 0.05) %>% layout(title = 'PV vs HDI')
subplot(my_plot[24:29], nrows = 2, margin = 0.05) %>% layout(title = 'RQ vs HDI')
subplot(my_plot[30], nrows = 1, margin = 0.05) %>% layout(title = 'RL vs HDI')

No se ve una relacion clara, hay tanto paises con punteos altos y bajos de GOB que tienen tanto HID altos o bajos Quiza puede verse una leve relacion de mayor punteo en GOB acompañado de mejor punteo den HDI

Se realizara el mismo proceso con el crecimiento o decrecimiento de HDI anual (no se perderan datos al calcular la diferencia porque se añade el año 2001 en la seleccion)

Manipulacion de datos utilizando operador diferencia

datos_model_2 <- datos_paper %>% 
        filter(!iso2c %in% c('SS', 'ZW', 'BT', 'ER', 'GW', 'KP', 'LB', 'NG', 'PS', 'SO', 'VU', 'FM', 'KI', 'TL', 'CV', 'SB'),
               !year %in% c(1995, 1996, 1997, 1998, 1999, 2000)) %>%
        select(iso2c, year, hdi, DT.ODA.ALLD.CD, DT.ODA.ALLD.KD, DT.ODA.ODAT.CD, DT.ODA.ODAT.KD, DT.ODA.ODAT.PC.ZS,
               all_of(gsub("_", ".", gob_indicators))
               )

vis_dat(datos_model_2)

datos_model_3 <- datos_model_2 %>%
  arrange(iso2c, year) %>%
  mutate(hdi_diff = hdi - lag(hdi)) %>%
  filter(!year %in% c(2001))

datos_model_3 %>% select(iso2c, year, hdi, hdi_diff)
vis_dat(datos_model_3)

Construccion de graficos

my_plot_3  <- list()

for (col in colnames(datos_model_3)[4:33]) {
  my_plot_3[[col]] <- plot_ly(x = datos_model_3[[col]], y = datos_model_3[[34]],
                            type = 'scatter', mode = 'markers', name = paste(col, "vs HDI diff"))  
}


subplot(my_plot_3[1:5], nrows = 2, margin = 0.05) %>% layout(title = 'ODA vs HDI')
subplot(my_plot_3[6:11], nrows = 2, margin = 0.05) %>% layout(title = 'CC vs HDI diff')
subplot(my_plot_3[12:17], nrows = 2, margin = 0.05) %>% layout(title = 'GE vs HDI diff')
subplot(my_plot_3[18:23], nrows = 2, margin = 0.05) %>% layout(title = 'PV vs HDI diff')
subplot(my_plot_3[24:29], nrows = 2, margin = 0.05) %>% layout(title = 'RQ vs HDI diff')
subplot(my_plot_3[30], nrows = 1, margin = 0.05) %>% layout(title = 'RL vs HDI diff')

Probar un nuevo modelo usadno ahora como variable dependiente hdi_diff

model_3 <- lm(hdi_diff ~ DT.ODA.ALLD.CD + CC.EST + GE.EST + PV.EST + RQ.EST + RL.EST, data=datos_model_3)
summary(model_3)
## 
## Call:
## lm(formula = hdi_diff ~ DT.ODA.ALLD.CD + CC.EST + GE.EST + PV.EST + 
##     RQ.EST + RL.EST, data = datos_model_3)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.084650 -0.002575  0.000074  0.002727  0.074605 
## 
## Coefficients:
##                  Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     6.437e-03  4.444e-04  14.485  < 2e-16 ***
## DT.ODA.ALLD.CD -6.826e-14  1.978e-13  -0.345  0.73005    
## CC.EST          6.344e-04  8.289e-04   0.765  0.44421    
## GE.EST          2.211e-03  8.457e-04   2.615  0.00905 ** 
## PV.EST          1.058e-03  3.448e-04   3.070  0.00219 ** 
## RQ.EST         -1.227e-03  8.134e-04  -1.509  0.13169    
## RL.EST         -2.355e-03  9.200e-04  -2.560  0.01060 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.006801 on 1091 degrees of freedom
## Multiple R-squared:  0.01844,    Adjusted R-squared:  0.01304 
## F-statistic: 3.416 on 6 and 1091 DF,  p-value: 0.002404

Otro modelo ahora usando las variables PER.RNK en vex de EST

model_4 <- lm(hdi_diff ~ DT.ODA.ALLD.CD + CC.PER.RNK + GE.PER.RNK + PV.PER.RNK + RQ.PER.RNK + RL.EST, data=datos_model_3)
summary(model_4)
## 
## Call:
## lm(formula = hdi_diff ~ DT.ODA.ALLD.CD + CC.PER.RNK + GE.PER.RNK + 
##     PV.PER.RNK + RQ.PER.RNK + RL.EST, data = datos_model_3)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.085300 -0.002458  0.000048  0.002847  0.074421 
## 
## Coefficients:
##                  Estimate Std. Error t value Pr(>|t|)   
## (Intercept)     4.239e-03  1.620e-03   2.616  0.00902 **
## DT.ODA.ALLD.CD -2.927e-13  1.917e-13  -1.527  0.12711   
## CC.PER.RNK      2.002e-05  2.154e-05   0.930  0.35272   
## GE.PER.RNK      4.254e-05  2.599e-05   1.637  0.10192   
## PV.PER.RNK      9.925e-06  1.451e-05   0.684  0.49422   
## RQ.PER.RNK     -3.012e-05  2.547e-05  -1.182  0.23733   
## RL.EST         -1.296e-03  9.288e-04  -1.395  0.16323   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.006842 on 1091 degrees of freedom
## Multiple R-squared:  0.006585,   Adjusted R-squared:  0.001122 
## F-statistic: 1.205 on 6 and 1091 DF,  p-value: 0.3009

Viendo la historia de las variables en el tiempo (por pais)

datos_model_3 %>% filter(iso2c == 'AF') %>% plot_ly(x = ~year) %>% 
  add_trace(y = ~hdi, type = 'scatter', mode = 'lines+markers', name = 'hdi') %>% 
  add_trace(y = ~hdi_diff, type = 'scatter', mode = 'lines+markers', name = 'hdi diff') %>% 
  add_trace(y = ~DT.ODA.ALLD.CD / 10000000000, type = 'scatter', mode = 'lines+markers', name = 'ODA')  %>% 
  add_trace(y = ~CC.EST, type = 'scatter', mode = 'lines+markers', name = 'CC') %>% 
  add_trace(y = ~GE.EST, type = 'scatter', mode = 'lines+markers', name = 'GE')  %>% 
  add_trace(y = ~PV.EST, type = 'scatter', mode = 'lines+markers', name = 'PV')  %>% 
  add_trace(y = ~RQ.EST, type = 'scatter', mode = 'lines+markers', name = 'RQ')  %>% 
  add_trace(y = ~RL.EST, type = 'scatter', mode = 'lines+markers', name = 'RL')